import React from "react";
import {
  CombinedBookingIds,
  CourseEventReferenceShape,
} from "@/components/c08-CoursePickerGroup";
import { ExhibitionEventReferenceShape } from "@/components/c38-ExhibitionPickerGroup";
import {
  AddressFieldShape,
  UserPageShape,
  UserShape,
} from "@/data/user/userTypes";
import { EMPTY_USER } from "@/data/user/userData";
import Taro, { chooseAddress } from "@tarojs/taro";
import { navigateTo } from "@/utils/navigation";
import { ApiItemTypeMapping } from "@/data/shared/entityShapes";
import { apiItemTypeMapping } from "@/utils/apiMapping";
import { AuthAction, apiWithAuth } from "@/store/authContext";
import { alert, error } from "@/utils/alert";
import {
  ApiInvoiceType,
  InvoicableOrdersResponseShape,
  InvoiceDetailShape,
  InvoiceHistoryShape,
} from "@/data/invoice/invoiceTypes";
import {
  OrderDetailShape,
  OrderPaymentStatusResponseShape,
} from "@/data/order/orderTypes";
import { RefundDetailResponse } from "@/data/refund/refundData";
import { userPageMockData } from "../../.local/mock-data/user";

type MiscShape = {
  query?: any;
  method?: "POST" | "GET";
  authDispatch?: React.Dispatch<AuthAction>;
};

type ErrorMessage = { errorMsg: string };
export type UserAction =
  | { type: "USER_DATA_FETCH"; data?: never; error?: never }
  | { type: "USER_DATA_SUCCESS"; data: UserShape; error?: never }
  | { type: "USER_DATA_FAIL"; data?: never; error: ErrorMessage }
  | { type: "USERPAGE_DATA_FETCH"; data?: never; error?: never }
  | { type: "USERPAGE_DATA_SUCCESS"; data: UserPageShape; error?: never }
  | { type: "USERPAGE_DATA_FAIL"; data?: never; error: ErrorMessage }
  | {
    type: "ADDRESS_EDIT_SELECT";
    data: (AddressFieldShape & { canBeDeleted: boolean }) | null;
    error?: never;
  }
  | {
    type: "COURSE_EVENT_SELECT";
    data: {
      bookingId: CombinedBookingIds;
      type: "course" | "bundlecourse";
      bookingData: CourseEventReferenceShape;
    } | null;
    error?: never;
  }
  | {
    type: "EXHIBITION_EVENT_SELECT";
    data: ExhibitionEventReferenceShape | null;
    error?: never;
  }
  | {
    type: "CART_SELECT";
    data: number[] | null;
    error?: never;
  }
  | {
    type: "CART_QUANTITY_UPDATE";
    data: { id: number; quantity: number };
    error?: never;
  }
  | {
    type: "REFUND_SELECT";
    data: number[] | null;
    error?: never;
  }
  | {
    type: "LIVE_LINK";
    data: string | null;
    error?: never;
  }
  | {
    type: "ORDER";
    data: UserInfoState["orderNos"] | null;
    error?: never;
  };

type Dispatch = (action: UserAction) => void;

export interface UserInfoState {
  userDataLoading: boolean;
  userDataError: null | ErrorMessage;
  userData: null | UserShape;
  userPageDataLoading: boolean;
  userPageDataError: null | ErrorMessage;
  userPageData: null | UserPageShape;
  addressEditData: (AddressFieldShape & { canBeDeleted: boolean }) | null;
  selectedCourseData: {
    [key: CombinedBookingIds]: CourseEventReferenceShape;
  };
  selectedEventData: ExhibitionEventReferenceShape | null;
  selectedCartData: number[] | null;
  selectedRefundData: number[] | null;
  liveLink: string | null;
  orderNos?: string[] | null;
}

// @ts-ignore
const UserInfoContext = React.createContext<{
  userInfoState: UserInfoState;
  dispatchUserDataAction: Dispatch;
  requestWechatAddress: () => Promise<void>;
}>();

const reducer = (
  state: UserInfoState,
  { type, data, error }: UserAction
): UserInfoState => {
  switch (type) {
    case "USER_DATA_FETCH":
      return {
        ...state,
        userDataLoading: true,
      };
    case "USER_DATA_SUCCESS":
      return {
        ...state,
        userDataLoading: false,
        userData: data,
      };
    case "USER_DATA_FAIL":
      return {
        ...state,
        userDataLoading: false,
        userDataError: error,
      };
    case "USERPAGE_DATA_FETCH":
      return {
        ...state,
        userPageDataLoading: true,
      };
    case "USERPAGE_DATA_SUCCESS":
      return {
        ...state,
        userPageDataLoading: false,
        userPageData: data,
      };
    case "USERPAGE_DATA_FAIL":
      return {
        ...state,
        userPageDataLoading: false,
        userPageDataError: error,
      };
    case "ADDRESS_EDIT_SELECT":
      return {
        ...state,
        addressEditData: data,
      };
    case "COURSE_EVENT_SELECT":
      if (!data) {
        return { ...state, selectedCourseData: {} };
      }
      const [primId, secondId] = data.bookingId.split("-");
      // Single course -> simply update state
      if (data.type === "course") {
        return {
          ...state,
          selectedCourseData: {
            [data.bookingId]: data.bookingData,
          },
        };
      }
      // if new primary ID, need to remove any existing values
      if (
        Object.keys(state.selectedCourseData).filter((key) => {
          const [primIdInObj] = key.split("-");
          return primIdInObj !== primId;
        }).length
      ) {
        return {
          ...state,
          selectedCourseData: {
            [data.bookingId]: data.bookingData,
          },
        };
      }

      // Reaching here, must be combined course
      return {
        ...state,
        selectedCourseData: {
          ...state.selectedCourseData,
          [data.bookingId]: data.bookingData,
        },
      };
      break;
    case "EXHIBITION_EVENT_SELECT":
      if (!data) {
        return { ...state, selectedEventData: null };
      } else {
        // Don't update if same ID
        if (data.schedulingId === state.selectedEventData?.schedulingId) {
          return state;
        }
        return { ...state, selectedEventData: data };
      }
      break;
    case "CART_SELECT":
      if (!data) {
        return { ...state, selectedCartData: null };
      } else {
        return { ...state, selectedCartData: data };
      }
      break;
    // TEMP -> NO REQUEST SUBMITTED
    case "CART_QUANTITY_UPDATE":
      if (state.userData) {
        const updatedCartData = state.userData.cart.map((cartItem) => {
          if (cartItem.id === data.id) {
            return { ...cartItem, quantity: data.quantity };
          } else {
            return cartItem;
          }
        });
        return {
          ...state,
          userData: { ...state.userData, cart: updatedCartData },
        };
      } else {
        return state;
      }
      break;
    case "REFUND_SELECT":
      if (!data) {
        return { ...state, selectedRefundData: null };
      } else {
        return { ...state, selectedRefundData: data };
      }
      break;
    case "LIVE_LINK":
      if (!data) {
        return { ...state, liveLink: null };
      } else {
        return { ...state, liveLink: data };
      }
      break;

    case "ORDER":
      return {
        ...state,
        orderNos: data,
      };
      break;

    default:
      throw new Error(`Unhandled action type: ${type}`);
  }
};

// Action helpers (complex actions, mainly async calls)
export const getUserData = async (
  dispatch: React.Dispatch<UserAction>,
  originalData: UserShape,
  misc?: any
) => {
  return await apiWithAuth(
    "/user/info",
    (res) => {
      const { data, code } = res.data;
      if (code === 200) {
        dispatch({
          type: "USER_DATA_SUCCESS",
          data: {
            ...originalData,
            userInfo: {
              ...originalData.userInfo,
              title: data.sex === 1 ? "先生" : "女士",
              uid: data.uid,
              nickName: data.nickname,
              fullName: data.realName,
              phoneNumber: data.phone,
              email: data.email,
              residenceArea: data.address,
              birthDay: data.birthday,
              collectionCount: data.collectionCount,
              coursesCount: data.coursesCount,
              talkCount: data.talkCount,
              giftCardsCount: data.giftCardsCount,
              exhibitionsCount: data.exhibitionsCount,
              shoppingCartsCount: data.shoppingCartsCount,
              lineUpResponses: data.lineUpResponses,
              noGetAppoinment: originalData.userInfo.noGetAppoinment.length
                ? originalData.userInfo.noGetAppoinment
                : data.noGetAppoinment,
              defaultAddress: {
                id: data.userAddress.id,
                phone: data.userAddress.phone,
                name: data.userAddress.realName,
                residenceArea: data.userAddress.address,
                address: data.userAddress.detail,
                isPrimary: data.userAddress.isDefault,
              },
            },
          },
        });
        return true;
      } else {
        return false;
      }
    },
    misc
  );
};

export const setUserData = async (
  dispatch: React.Dispatch<UserAction>,
  originalData: UserShape,
  misc: MiscShape
) => {
  return await apiWithAuth(
    "/user/edit",
    (res) => {
      const { message } = res.data;
      if (message === "操作成功") {
        alert(message);
        dispatch({
          type: "USER_DATA_SUCCESS",
          data: {
            ...originalData,
            userInfo: {
              ...originalData.userInfo,
              title: misc.query.title,
              nickName: misc.query.nickname,
              phoneNumber: misc.query.phone,
              email: misc.query.email,
              residenceArea: misc.query.address,
              birthDay: misc.query.birthday,
            },
          },
        });
        return true;
      } else {
        return false;
      }
    },
    misc
  );
};

export const getUserAddressList = async (
  dispatch: React.Dispatch<UserAction>,
  originalData: UserShape,
  misc: MiscShape
) => {
  return await apiWithAuth(
    "/address/list",
    (res) => {
      const { message, code, data } = res.data;
      if (code === 200 && message === "操作成功") {
        const deliveryAddress = data.list.map((da: any) => {
          return {
            id: da.id,
            title: da.title,
            residenceArea: da.address,
            address: da.detail,
            name: da.realName,
            phone: da.phone,
            isPrimary: da.isDefault,
          };
        });
        dispatch({
          type: "USER_DATA_SUCCESS",
          data: {
            ...originalData,
            userInfo: {
              ...originalData.userInfo,
              deliveryAddress: deliveryAddress,
            },
          },
        });
        return true;
      } else {
        return false;
      }
    },
    {
      query: {
        limit: process.env.defaultPageSize!,
        page: 1,
      },
      authDispatch: misc.authDispatch,
    }
  );
};

export const addUserAddress = async (
  dispatch: React.Dispatch<UserAction>,
  originalData: UserShape,
  misc: MiscShape
) => {
  dispatch({ type: "USER_DATA_FETCH" });
  try {
    await apiWithAuth(
      "/address/edit",
      (res) => {
        const { message, code } = res.data;
        if (code === 200 && message === "操作成功") {
          Taro.navigateBack();
          return true;
        } else {
          error(message);
          return false;
        }
      },
      { query: misc.query, method: "POST" }
    );
  } catch (error) {
    dispatch({ type: "USER_DATA_FAIL", error });
    return false;
  }
};

export const removeUserAddress = async (
  dispatch: React.Dispatch<UserAction>,
  misc: MiscShape
) => {
  try {
    await apiWithAuth(
      "/address/del",
      (res) => {
        const { code, message } = res.data;
        if (code === 200) {
          alert(message);
          Taro.navigateBack();
          return true;
        } else {
          error(message);
          return false;
        }
      },
      { query: misc.query, method: "POST", authDispatch: misc.authDispatch }
    );
  } catch (error) {
    dispatch({ type: "USER_DATA_FAIL", error });
    return false;
  }
};

export const setUserDefaultAddress = async (
  dispatch: React.Dispatch<UserAction>,
  originalData: UserShape,
  misc: MiscShape
) => {
  return await apiWithAuth(
    "/address/default/set",
    (res) => {
      const { message, code, data } = res.data;
      if (code === 200 && message === "操作成功") {
        const deliveryAddress = {
          id: data.id,
          title: data.title,
          residenceArea: data.address,
          address: data.detail,
          name: data.realName,
          phone: data.phone,
          isPrimary: data.isDefault,
        };
        dispatch({
          type: "USER_DATA_SUCCESS",
          data: {
            ...originalData,
            userInfo: {
              ...originalData.userInfo,
              defaultAddress: deliveryAddress,
            },
          },
        });
        return true;
      } else {
        error(message);
        return false;
      }
    },
    {
      query: misc.query,
      method: "POST",
    }
  );
};

export const getUserFav = async (
  dispatch: React.Dispatch<UserAction>,
  originalData: UserShape,
  misc: MiscShape
) => {
  dispatch({ type: "USER_DATA_FETCH" });
  try {
    await apiWithAuth(
      "/user/collection",
      (res) => {
        const { data } = res.data;
        dispatch({
          type: "USER_DATA_SUCCESS",
          data: {
            ...originalData,
            likedItems: data.list,
          },
        });
        return true;
      },
      misc
    );
  } catch (error) {
    dispatch({ type: "USER_DATA_FAIL", error });
    return false;
  }
};

export const addRemoveUserFav = async (misc: MiscShape) => {
  const { query, authDispatch } = misc;
  return await apiWithAuth(
    `/collection/collect?mainId=${query.mainId}&type=${query.type}`,
    (res) => {
      const { data } = res;
      if (data.code === 200) {
        alert(data.message);
        if (data.message === "收藏成功") {
          return true;
        } else if (data.message === "取消收藏成功") {
          return false;
        }
      } else {
        //error(data.message);
        return null;
      }
    },
    {
      method: "POST",
      authDispatch: authDispatch,
    }
  );
};

export const getUserCart = async (
  dispatch: React.Dispatch<UserAction>,
  originalData: UserShape,
  misc: MiscShape
) => {
  return await apiWithAuth(
    "/cart/list",
    (res) => {
      const { data } = res.data;
      dispatch({
        type: "USER_DATA_SUCCESS",
        data: {
          ...originalData,
          cart: data.list,
        },
      });
      return true;
    },
    misc
  );
};

export const addUserCart = async (
  dispatch: React.Dispatch<UserAction>,
  originalData: UserShape,
  misc: MiscShape
) => {
  return await apiWithAuth(
    "/cart/save",
    (res) => {
      const { data } = res;
      if (data.code === 200) {
        alert(data.message);
        const successData = data.data as {
          cartId: string;
          cartQuantity: string;
        };
        dispatch({
          type: "USER_DATA_SUCCESS",
          data: {
            ...originalData,
            userInfo: {
              ...originalData.userInfo,
              shoppingCartsCount: +successData.cartQuantity,
            },
          },
        });
        return data.data.cartId;
      } else {
        error(data.message);
      }
    },
    misc
  );
};

export const changeUserCart = async (
  dispatch: React.Dispatch<UserAction>,
  misc: MiscShape
) => {
  return await apiWithAuth(
    `/cart/num?id=${misc.query.id}&number=${misc.query.quantity}`,
    (res) => {
      const { message, code } = res.data;
      if (code === 200 && message === "操作成功") {
        alert(message);
        dispatch({
          type: "CART_QUANTITY_UPDATE",
          data: {
            id: misc.query.id,
            quantity: misc.query.quantity,
          },
        });
        return true;
      } else {
        error(message);
        return false;
      }
    },
    {
      method: "POST",
      authDispatch: misc.authDispatch,
    }
  );
};

export const removeUserCart = async (
  dispatch: React.Dispatch<UserAction>,
  originalData: UserShape,
  misc: MiscShape
) => {
  return await apiWithAuth(
    `/cart/delete?ids=${misc.query.ids.join("&ids=")}`,
    (res) => {
      const { message, code } = res.data;
      if (code === 200 && message === "操作成功") {
        alert(message);
        const newCart = originalData.cart.filter((c: any) => {
          return !misc.query.ids.includes(c.id);
        });
        dispatch({
          type: "USER_DATA_SUCCESS",
          data: {
            ...originalData,
            userInfo: {
              ...originalData.userInfo,
              shoppingCartsCount:
                originalData.userInfo.shoppingCartsCount - 1 < 0
                  ? 0
                  : originalData.userInfo.shoppingCartsCount - 1,
            },
            cart: newCart,
          },
        });
        return true;
      } else {
        error(message);
        return false;
      }
    },
    {
      method: "POST",
      authDispatch: misc.authDispatch,
    }
  );
};

export const getUserGifts = async (
  dispatch: React.Dispatch<UserAction>,
  originalData: UserShape,
  misc: MiscShape
) => {
  return await apiWithAuth(
    "/user/card",
    (res) => {
      const { code, data, message } = res.data;
      if (code !== 200) {
        error(message);
      } else {
        if (!misc.query.preOrderNo) {
          dispatch({
            type: "USER_DATA_SUCCESS",
            data: {
              ...originalData,
              giftCertificates: data.list,
            },
          });
          return true;
        } else {
          return data.list;
        }
      }
      return true;
    },
    misc
  );
};

export const addUserGiftCard = async (
  misc: MiscShape,
  onSuccess: () => void,
) => {
  const { cardKey } = misc.query;
  return await apiWithAuth(
    `/user/exchangeCard?cardKey=${cardKey}`,
    (res) => {
      const { code, message } = res.data;
      if (code !== 200) {
        error(message);
      } else {
        onSuccess();
      }
      return true;
    },
    misc
  );
};

export const getUserQr = async (
  dispatch: React.Dispatch<UserAction>,
  originalData: UserShape,
  misc
) => {
  dispatch({ type: "USER_DATA_FETCH" });
  try {
    await apiWithAuth(
      "/user/qrcode",
      (res) => {
        const { data } = res.data;
        dispatch({
          type: "USER_DATA_SUCCESS",
          data: {
            ...originalData,
            userInfo: {
              ...originalData.userInfo,
              userQrCode: data.qrCode,
            },
          },
        });
        return true;
      },
      misc
    );
  } catch (error) {
    dispatch({ type: "USER_DATA_FAIL", error });
    return false;
  }
};

export const getUserEvents = async (
  dispatch: React.Dispatch<UserAction>,
  originalData: UserShape,
  misc
) => {
  dispatch({ type: "USER_DATA_FETCH" });
  try {
    await apiWithAuth(
      "/user/appointment",
      (res) => {
        const { data } = res.data;
        const past = data.list.filter((p) => {
          return p.status == 2;
        });
        const up = data.list.filter((p) => {
          return p.status == 1;
        });
        const newData = {};
        newData[apiItemTypeMapping[misc.query.mainType]] = {
          past: past,
          upcoming: up,
        };
        dispatch({
          type: "USER_DATA_SUCCESS",
          data: {
            ...originalData,
            userEvents: {
              ...originalData.userEvents,
              ...newData,
            },
          },
        });
        return true;
      },
      misc
    );
  } catch (error) {
    dispatch({ type: "USER_DATA_FAIL", error });
    return false;
  }
};

export const getUserWaitList = async (
  dispatch: React.Dispatch<UserAction>,
  originalData: UserShape,
  misc: MiscShape
) => {
  return await apiWithAuth(
    "/line/up/list",
    (res) => {
      const { data } = res;
      if (data.code === 200) {
        dispatch({
          type: "USER_DATA_SUCCESS",
          data: {
            ...originalData,
            waitingList: data.data.list,
          },
        });
        return true;
      } else {
        error(data.message);
        return null;
      }
    },
    {
      query: misc.query,
      authDispatch: misc.authDispatch,
    }
  );
};

export const addToLineUp = async (misc: MiscShape) => {
  const { type, mainId } = misc.query;
  return await apiWithAuth(
    `/line/up/line/up?mainId=${mainId}&type=${type}`,
    (res) => {
      const { message, code } = res.data;
      if (code === 200 && message === "操作成功") {
        alert(message);
        return true;
      } else {
        error(message);
        return false;
      }
    },
    {
      method: "POST",
    }
  );
};

export const removeFromLineUp = async (misc: MiscShape) => {
  const { lineUpId } = misc.query;
  return await apiWithAuth(
    `/line/up/remove?lineUpId=${lineUpId}`,
    (res) => {
      const { message, code } = res.data;
      if (code === 200 && message === "操作成功") {
        alert(message);
        return true;
      } else {
        error(message);
        return false;
      }
    },
    {
      query: misc.query,
      authDispatch: misc.authDispatch,
    }
  );
};

export const getUserOrderList = async (
  dispatch: React.Dispatch<UserAction>,
  originalData: UserShape,
  misc
) => {
  dispatch({ type: "USER_DATA_FETCH" });
  try {
    await apiWithAuth(
      "/order/list",
      (res) => {
        const { data } = res.data;
        const eventsArray = data.list.filter((p: any) => {
          return p.type !== ApiItemTypeMapping.ShopItem;
        });
        const events = eventsArray.map((e: any) => {
          return {
            id: e.id,
            orderNo: e.orderNo,
            imagePath: e.images[0],
            themeColor: e.themeColor,
            tagText: e.tagText,
            name: e.name,
            date: e.date,
            startTime: e.startTime,
            endTime: e.endTime,
            upperRightText: e.orderStatus,
          };
        });
        const storeItemsArray = data.list.filter((p) => {
          return p.type === ApiItemTypeMapping.ShopItem;
        });
        const storeItems = storeItemsArray.map((s: any) => {
          return {
            id: s.id,
            orderDate: s.createTime,
            deliveryStatus: s.orderStatus,
            orderNumber: s.orderNo,
            thumbNails: s.images,
            totalItemsOrdered: s.totalNum,
            orderTotalPrice: s.payPrice,
          };
        });
        dispatch({
          type: "USER_DATA_SUCCESS",
          data: {
            ...originalData,
            orderHistory: {
              events: events,
              storeItems: storeItems,
            },
          },
        });
        return true;
      },
      misc
    );
  } catch (error) {
    dispatch({ type: "USER_DATA_FAIL", error });
    return false;
  }
};

export const getUserPageData = async (dispatch: React.Dispatch<UserAction>) => {
  // TODO: this may be the best place to perform auth?
  dispatch({ type: "USERPAGE_DATA_FETCH" });
  try {
    // api(
    //   "/user/info",
    //   (res)=> {
    //     console.log(res)
    //     dispatch({ type: "USERPAGE_DATA_SUCCESS", data: userPageMockData });
    //     return true;
    //   }
    // )
    dispatch({ type: "USERPAGE_DATA_SUCCESS", data: userPageMockData });
    return true;
  } catch (error) {
    dispatch({ type: "USERPAGE_DATA_FAIL", error });
    return false;
  }
};

export const placeOrder = async (misc: MiscShape) => {
  return await apiWithAuth(
    "/order/pre/order/common",
    (res) => {
      const { data } = res;
      if (data.code === 200) {
        return data.data.preOrderNo;
      } else {
        error(data.message);
        return null;
      }
    },
    {
      query: misc.query,
      method: "POST",
      authDispatch: misc.authDispatch,
    }
  );
};

export const returnOrder = async (misc: MiscShape) => {
  return await apiWithAuth(
    "/order/refund/order",
    (res) => {
      const { message, code } = res.data;
      if (code === 200 && message === "操作成功") {
        alert(message);
        return true;
      } else {
        error(message);
        return false;
      }
    },
    {
      query: misc.query,
      method: "POST",
      authDispatch: misc.authDispatch,
    }
  );
};

export const returnOrderUpdate = async (misc: MiscShape) => {
  return await apiWithAuth(
    "/order/refund/update",
    (res) => {
      const { message, code } = res.data;
      if (code === 200 && message === "操作成功") {
        alert(message);
        return true;
      } else {
        error(message);
        return false;
      }
    },
    {
      query: misc.query,
      method: "POST",
      authDispatch: misc.authDispatch,
    }
  );
};

export const refundProduct = async (misc: MiscShape) => {
  return await apiWithAuth(
    `/order/product/cancel?orderId=${misc.query.orderNo}`,
    (res) => {
      const { message, code } = res.data;
      if (code === 200 && message === "操作成功") {
        alert(message);
        return true;
      } else {
        error(message);
        return false;
      }
    },
    {
      method: "POST",
      authDispatch: misc.authDispatch,
    }
  );
};

export const cancelReturnOrder = async (misc: MiscShape) => {
  return await apiWithAuth(
    `/order/refund/order/cancel?orderNo=${misc.query.orderNo}`,
    (res) => {
      const { message, code } = res.data;
      if (code === 200 && message === "操作成功") {
        alert(message);
        return true;
      } else {
        error(message);
        return false;
      }
    },
    {
      method: "POST",
      authDispatch: misc.authDispatch,
    }
  );
};

export const confirmOrder = async (misc: MiscShape) => {
  return await apiWithAuth(
    `/order/take?orderNo=${misc.query.orderNo}`,
    (res) => {
      const { message, code } = res.data;
      if (code === 200 && message === "操作成功") {
        alert(message);
        return true;
      } else {
        error(message);
        return false;
      }
    },
    {
      method: "POST",
      authDispatch: misc.authDispatch,
    }
  );
};

export const generateKey = async (misc: MiscShape) => {
  return await apiWithAuth(
    `/vhall/generateKey/?talkId=${misc.query.id}`,
    (res) => {
      const { data } = res;
      if (data.code === 200) {
        return data.message;
      } else {
        error(data.message);
        return null;
      }
    }
  );
};

export const getOrderCheckout = async (misc: MiscShape) => {
  return await apiWithAuth(
    `/order/load/pre/common/${misc.query.preOrderNo}`,
    (res) => {
      const { data } = res;
      if (data.code === 200) {
        return data.data;
      } else {
        error(data.message);
        return null;
      }
    },
    { authDispatch: misc.authDispatch }
  );
};

export const setOrderPrice = async (misc: MiscShape) => {
  return await apiWithAuth(
    `/order/computed/common/price`,
    (res) => {
      const { data } = res;
      if (data.code === 200) {
        return data.data;
      } else {
        error(data.message);
        return null;
      }
    },
    {
      query: misc.query,
      method: "POST",
      authDispatch: misc.authDispatch,
    }
  );
};

export const getOrderDetail: (
  misc: MiscShape
) => Promise<OrderDetailShape | null> = async (misc) => {
  return await apiWithAuth(
    `/order/detail/${misc.query.orderNo}`,
    (res) => {
      const { data } = res;
      if (data.code === 200) {
        return data.data as OrderDetailShape;
      } else {
        error(data.message);
        return null;
      }
    },
    { authDispatch: misc.authDispatch }
  );
};

export const cancelOrder = async (misc: MiscShape) => {
  return await apiWithAuth(
    `/order/cancel?orderNo=${misc.query.orderNo}`,
    (res) => {
      const { data } = res;
      if (data.code === 200) {
        alert(data.message);
        return data.message;
      } else {
        error(data.message);
        return null;
      }
    },
    {
      method: "POST",
      authDispatch: misc.authDispatch,
    }
  );
};

export const requestRefund = async (misc: MiscShape) => {
  return await apiWithAuth(
    `/order/apply/refund/${misc.query.orderNo}`,
    (res) => {
      const { data } = res;
      if (data.code === 200) {
        return data.data;
      } else {
        error(data.message);
        return null;
      }
    },
    { authDispatch: misc.authDispatch }
  );
};

export const submitRefund = async (misc: MiscShape) => {
  return await apiWithAuth(
    `/order/refund/`,
    (res) => {
      const { message, code } = res.data;
      if (code === 200 && message === "操作成功") {
        alert(message);
        return true;
      } else {
        error(message);
        return false;
      }
    },
    { query: misc.query, method: "POST", authDispatch: misc.authDispatch }
  );
};

export const getRefundDetail: (
  misc: MiscShape
) => Promise<RefundDetailResponse | null> = async (misc: MiscShape) => {
  return await apiWithAuth(
    "/order/refund/info/",
    (res) => {
      const { data } = res;
      if (data.code === 200) {
        return data.data as RefundDetailResponse;
      } else {
        error(data.message);
        return null;
      }
    },
    {
      query: misc.query,
      authDispatch: misc.authDispatch,
    }
  );
};

export const cancelRefund = async (misc: MiscShape) => {
  return await apiWithAuth(
    `/order/refund/revocation/?orderNo=${misc.query.orderNo}`,
    (res) => {
      const { message, code } = res.data;
      if (code === 200 && message === "操作成功") {
        alert(message);
        return true;
      } else {
        error(message);
        return false;
      }
    },
    {
      method: "POST",
      authDispatch: misc.authDispatch,
    }
  );
};

export const submitOrder = async (
  dispatch: React.Dispatch<UserAction>,
  misc: MiscShape
) => {
  return await apiWithAuth(
    `/order/create/common/order`,
    (res) => {
      const { data } = res;
      if (data.code === 200) {
        if (data.data && data.data.orderNo) {
          dispatch({ type: "ORDER", data: data.data.orderNo });
          return data.data.orderNo;
        }
      } else {
        error(data.message);
        return null;
      }
    },
    {
      query: misc.query,
      method: "POST",
      authDispatch: misc.authDispatch,
    }
  );
};

export const getPaymentInfo = async (misc: MiscShape) => {
  return await apiWithAuth(
    `/order/payment/pre/order`,
    (res) => {
      const { data } = res;
      if (data.code === 200) {
        return data.data;
      } else {
        error(data.message);
        return null;
      }
    },
    {
      query: misc.query,
      method: "POST",
      authDispatch: misc.authDispatch,
    }
  );
};

export const getOrderStatus = async (
  dispatch: React.Dispatch<UserAction>,
  misc: MiscShape
) => {
  return await apiWithAuth(
    `/order/payment/query/status`,
    (res) => {
      const { data } = res;
      if (data.code === 200) {
        if (data.data.msg !== "待付款") {
          dispatch({ type: "ORDER", data: null });
        }
        return { status: data.data.msg, price: data.data.payFree };
      } else {
        error(data.msg);
        return null;
      }
    },
    {
      query: misc.query,
      method: "POST",
      authDispatch: misc.authDispatch,
    }
  );
};

export const getOrderPaymentStatus = async (
  misc: MiscShape
): Promise<OrderPaymentStatusResponseShape> => {
  return await apiWithAuth(
    `/order/payment/query/status`,
    (res) => {
      const { data } = res;
      if (data.code === 200) {
        return data.data as OrderPaymentStatusResponseShape;
      } else {
        error(data.message);
        return null;
      }
    },
    {
      query: misc.query,
      method: "POST",
      authDispatch: misc.authDispatch,
    }
  );
};

export const requestSubscribeMessage = (ids: string[], callback?: Function) => {
  Taro.requestSubscribeMessage({
    tmplIds: ids,
    success: callback && callback(),
    fail: callback && callback(),
  });
};

export const acceptGift = async (misc: MiscShape) => {
  const { query, authDispatch } = misc;
  const { orderInfoIds } = query;
  return await apiWithAuth(
    `/order/get?orderInfoIds=${orderInfoIds}`,
    (res) => {
      const { data } = res;
      if (data.code === 200) {
        alert(data.message);
        if (data.message === "收藏成功") {
          return true;
        } else if (data.message === "取消收藏成功") {
          return false;
        }
      } else {
        error(data.message);
        return null;
      }
    },
    {
      method: "POST",
      authDispatch: authDispatch,
    }
  );
};

export const snoozeLineUpNotification = async (misc: MiscShape) => {
  const { query, authDispatch } = misc;
  const { lineUpId } = query;
  return await apiWithAuth(
    `/line/up/disable?lineUpId=${lineUpId}`,
    (res) => {
      const { code, message } = res.data;
      if (code === 200 && message === "操作成功") {
        alert(message);
        return true;
      } else {
        error(message);
        return false;
      }
    },
    { authDispatch: authDispatch }
  );
};

/* Invoice APIs start */
export const getInvoiceHistory: (
  misc: MiscShape
) => Promise<InvoiceHistoryShape> = async (misc) => {
  return await apiWithAuth(
    "/invoice/invoicedRecord",
    (res) => {
      const { data } = res;
      if (data.code === 200) {
        return data.data as InvoiceHistoryShape;
      } else {
        error(data.message);
        return [];
      }
    },
    { authDispatch: misc.authDispatch }
  );
};

export const getInvoicableOrders: (
  misc: MiscShape
) => Promise<InvoicableOrdersResponseShape> = async (misc) => {
  const { query, authDispatch } = misc;
  const orderNo = query && query.orderNo ? query.orderNo : null;
  const endpoint = orderNo
    ? `/invoice/invoicedList?orderNo=${orderNo}`
    : "/invoice/invoicedList";
  return await apiWithAuth(
    endpoint,
    (res) => {
      const { data } = res;
      if (data.code === 200) {
        return data.data as InvoicableOrdersResponseShape;
      } else {
        error(data.message);
        return [];
      }
    },
    { authDispatch: authDispatch }
  );
};

export const getInvoiceDetails: (
  misc: MiscShape
) => Promise<InvoiceDetailShape | null> = async (misc) => {
  const { query, authDispatch } = misc;
  const { invoiceId } = query;
  return await apiWithAuth(
    `/invoice/invoicedDetails?invoiceId=${invoiceId}`,
    (res) => {
      const { data } = res;
      if (data.code === 200) {
        return data.data as InvoiceDetailShape;
      } else {
        error(data.message);
        return null;
      }
    },
    { authDispatch: authDispatch }
  );
};

export const submitInvoice: (payload: {
  email: string;
  orderNos: string[];
  type: ApiInvoiceType;
  // Mandatory for personal invoice
  name?: string;
  // Mandatory for company invoice
  companyTaxNumber?: string;
  corporateName?: string;
}) => Promise<number | null> = async (payload) => {
  return await apiWithAuth(
    "/invoice/invoice",
    (res) => {
      const { data } = res;
      if (data.code === 200) {
        // ID returned from API as data-field
        return data.data as number;
      } else {
        error(data.message);
        return null;
      }
    },
    { query: payload, method: "POST" }
  );
};

/* Invoice APIs end */

function UserInfoProvider({ children }) {
  const [userInfoState, dispatchUserDataAction] = React.useReducer(reducer, {
    userDataLoading: false,
    userDataError: null,
    userData: EMPTY_USER,
    userPageDataLoading: false,
    userPageDataError: null,
    userPageData: null,
    addressEditData: null,
    selectedCourseData: {},
    selectedEventData: null,
    selectedCartData: null,
    selectedRefundData: null,
    liveLink: null,
  });

  const requestWechatAddress = async () => {
    try {
      const add = await chooseAddress();
      const addressPayload: AddressFieldShape = {
        name: add.userName,
        residenceArea: [add.provinceName, add.countyName, add.countyName],
        address: add.detailInfo,
        phone: add.telNumber,
        isPrimary: true,
      };
      dispatchUserDataAction({
        type: "ADDRESS_EDIT_SELECT",
        data: { ...addressPayload, canBeDeleted: false },
      });
      navigateTo("pages/address-details-edit/index");
    } catch (error) {
      // No-op
    }
  };

  const value = { userInfoState, dispatchUserDataAction, requestWechatAddress };
  return (
    <UserInfoContext.Provider value={value}>
      {children}
    </UserInfoContext.Provider>
  );
}

function useUserInfo() {
  const context = React.useContext(UserInfoContext);
  if (context === undefined) {
    throw new Error("useUserInfo must be used within a UserInfoProvider");
  }
  return context;
}

export { UserInfoProvider, useUserInfo };
